package gptma.bo.services.project;

import gptma.bo.services.request.ClientRequestServices;
import gptma.bo.dao.project.ProjectDao;
import gptma.bo.model.employee.Employee;
import gptma.bo.model.project.Project;
import gptma.bo.model.request.ClientRequest;
import gptma.bo.model.task.Task;
import gptma.bo.services.task.TaskServices;
import gptma.bo.services.reporting.ReportingOrder;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.Session;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Stateless
public class ProjectServicesImpl implements ProjectServices {

	private static final Logger log = LoggerFactory
			.getLogger(ProjectServicesImpl.class);

	@Inject
	private ProjectDao projectDao;

	@EJB
	private ClientRequestServices clientRequestServices;

	@EJB
	private TaskServices taskServices;

	@Resource(mappedName = "jms/ConnectionFactory")
	private ConnectionFactory connectionFactory;

	@Resource(mappedName = "jms/Queue")
	private Queue queue;

	@Override
	public List<String> completeProjectName(String partialName) {
		return projectDao.completeProjectName(partialName);
	}

	@Override
	public List<Project> findAll() {
		return projectDao.findAll();
	}

	@Override
	public List<Task> findAssociatedTasks(Project project) {
		List<Task> ret = new ArrayList<Task>();

		List<Task> directlyAttached = projectDao
				.findDirectlyAttachedTasks(project);
		if (directlyAttached != null) {
			ret.addAll(directlyAttached);
		}

		List<ClientRequest> requests = projectDao.findRequests(project);
		List<Task> requestTasks;
		if (requests != null) {
			for (ClientRequest clientRequest : requests) {
				requestTasks = clientRequestServices.findTasks(clientRequest);
				if (requestTasks != null) {
					for (Task task : requestTasks) {
						if (!ret.contains(task)) {
							ret.add(task);
						}
					}
				}
			}
		}

		return ret;
	}

	@Override
	public Project findById(Long id) {
		return projectDao.findById(id);
	}
	
	@Override
	public Project findByName(String name) {
		return projectDao.findByName(name);
	}

	@Override
	public List<Project> findProjectsByName(String name) {
		return projectDao.findProjectsByName(name);
	}

	@Override
	public List<Task> findDirectlyAttachedTasks(Project project) {
		return projectDao.findDirectlyAttachedTasks(project);
	}

	@Override
	public int findRequestCount(Project project) {
		return projectDao.findRequestCount(project);
	}

	@Override
	public List<ClientRequest> findRequests(Project project) {
		return projectDao.findRequests(project);
	}

	@Override
	public float[] getProjectCharge(Project project) {
		float[] ret = new float[3];

		float sold = 0;
		float charged = 0;
		float etc = 0;

		List<ClientRequest> reqs = projectDao.findRequests(project);
		if (reqs != null) {
			for (ClientRequest clientRequest : reqs) {
				float[] reqCharge = clientRequestServices
						.getRequestCharge(clientRequest);

				sold += reqCharge[0];
				charged += reqCharge[1];
				etc += reqCharge[2];
			}
		}

		List<Task> directlyAttached = projectDao
				.findDirectlyAttachedTasks(project);
		if (directlyAttached != null) {
			for (Task task : directlyAttached) {
				sold += task.getSoldCharge();
				charged += taskServices.findConsolidatedCharge(task);
				etc += taskServices.getCurrentEtc(task);
			}
		}

		ret[0] = sold;
		ret[1] = charged;
		ret[2] = etc;

		return ret;
	}

	@Override
	public void generateReporting(Employee projectManager, Date startDate,
			Date endDate) {
		log.debug("Begin({}, {}, {}", new Object[] {projectManager, startDate, endDate});
		
		// asynchronous job: post it to a JMS queue
		ReportingOrder order = new ReportingOrder(projectManager, startDate,
				endDate);

		try {
			Connection con = connectionFactory.createConnection();
			Session sess = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
			ObjectMessage msg = sess.createObjectMessage(order);
			MessageProducer producer = sess.createProducer(queue);
			producer.send(msg);
		} catch (JMSException e) {
			log.error("Could not post job to JMS queue, error code: {}, msg: {}",
					e.getErrorCode(), e.getMessage());
		}

		log.debug("End");
	}

	@Override
	public void saveProject(Project project) {
		projectDao.save(project);
	}
}
